package com.example.canal.event.config;

import com.example.canal.common.annotation.DbChangeEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.util.ClassUtils;

import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author LiYuhang
 * @version 0.1
 * @application
 * @Date 2021/8/9 09:13
 */
@Configuration
@Slf4j
public class DbChangeProcessor implements InitializingBean {
    private final String BASE_PACKAGE = "com.example.canal";
    private final String RESOURCE_PATTERN = "/**/*.class";
    private static final ConcurrentHashMap<String, Class<? extends ApplicationEvent>> EVENT_MAP = new ConcurrentHashMap<>();

    private final Class eventClass = ApplicationEvent.class;


    /**
     * 根据tableName 获取 指定的event
     *
     * @param tableName
     * @return
     */

    public static Class<? extends ApplicationEvent> getDbChangeDetailEventByTableName(String tableName) {

        return EVENT_MAP.get(tableName);
    }


    /**
     * 扫描当前包下，所有的类，将 符合条件的event
     *
     * @throws Exception
     */
    @Override
    public void afterPropertiesSet() throws Exception {
        //spring工具类，可以获取指定路径下的全部类
        ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
        try {
            String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
                    ClassUtils.convertClassNameToResourcePath(BASE_PACKAGE) + RESOURCE_PATTERN;
            Resource[] resources = resourcePatternResolver.getResources(pattern);
            //MetadataReader 的工厂类
            MetadataReaderFactory readerfactory = new CachingMetadataReaderFactory(resourcePatternResolver);
            for (Resource resource : resources) {
                //用于读取类信息
                MetadataReader reader = readerfactory.getMetadataReader(resource);
                //扫描到的class
                String classname = reader.getClassMetadata().getClassName();
                Class<?> aClass = Class.forName(classname);
                // 判断当前类 是 ApplicationEvent.class 的子类
                if (eventClass.isAssignableFrom(aClass)) {
                    Class<? extends ApplicationEvent> clazz = (Class<ApplicationEvent>) aClass;
                    //判断是否有指定主解
                    DbChangeEvent dbChangeEvent = clazz.getAnnotation(DbChangeEvent.class);
                    if (dbChangeEvent != null) {
                        //将注解中的类型值作为key，对应的类作为 value
                        EVENT_MAP.put(dbChangeEvent.tableName().toLowerCase(),clazz);
                    }
                }
            }
        } catch (IOException | ClassNotFoundException e) {
            log.error("获取指定注解异常, msg:{}",e.getMessage(),e);
        }
    }
}
